package cc.xpcas.raft.network;

import cc.xpcas.raft.Configuration;
import cc.xpcas.raft.context.Context;
import cc.xpcas.raft.context.Peer;

/**
 * @author xp
 */
public abstract class Starter<ADDRESS extends Address> {

    protected ADDRESS checkAddress(Address address) {
        if (getAddressClass().isInstance(address)) {
            @SuppressWarnings("unchecked")
            ADDRESS address1 =  (ADDRESS) address;
            return address1;
        }
        return null;
    }

    protected abstract Class<ADDRESS> getAddressClass();

    public Context run(Configuration configuration) {
        Context context = new Context(configuration);

        ADDRESS localAddress = checkAddress(configuration.getAddress());
        if (localAddress == null) return null;
        Endpoint<ADDRESS> endpoint = initLocal(configuration, context, localAddress);
        context.setEndpoint(endpoint);
        context.getPoller().start(endpoint);

        configuration.getPeers().forEach((serverId, address0) -> {
            if (configuration.getServerId() == serverId) return;

            ADDRESS remoteAddress = checkAddress(address0);
            if (remoteAddress == null) return;

            Peer peer = initPeer(context, serverId, remoteAddress);
            context.getPeers().put(serverId, peer);
        });

        return context;
    }

    protected abstract Endpoint<ADDRESS> initLocal(Configuration configuration, Context context, ADDRESS address);

    protected abstract Peer initPeer(Context context, int serverId, ADDRESS address);
}
